<template>
  <a-spin :spinning="gridLayout.spinning" :tip="gridLayout.tip">
    <div class="work-page">
      <!-- 卡片操作区域 -->
      <div class="vue-grid-layout-tobbar">
        <div class="flex-between">
          <div class="info-view">
            <span>66项目</span>
          </div>
          <div class="btn-group flex1">
            <a-button v-if="gridLayout.mode === 'show'" @click.stop="onEditCardMode"><edit-outlined />编辑卡片</a-button>
            <a-button v-if="gridLayout.mode === 'edit'" @click.stop="onEditSucc"><check-outlined />完成编辑</a-button>
            <a-button v-if="gridLayout.mode === 'edit'" @click.stop="onCalcelEdit"><close-outlined />取消编辑</a-button>
            <a-button v-if="gridLayout.mode === 'edit'" type="primary" @click.stop="onOpenAddCardPop"><plus-outlined />添加卡片</a-button>
          </div>
        </div>
      </div>

      <!-- 卡片区域 -->
      <div class="vue-grid-layout-content">
        <div class="layout-box-view">
          <grid-layout
            ref="gridlayout"
            :layout="gridLayout.layout"
            :col-num="gridLayout.colNum"
            :row-height="100"
            :is-draggable="gridLayout.isdraggable"
            :is-resizable="gridLayout.isresizable"
            :is-mirrored="false"
            :vertical-compact="true"
            :use-css-transforms="true"
            class="grid-layout-comp"
            :class="[gridLayout.mode == 'edit' ? 'bg-edit-mode' : 'bg-show-mode']"
          >
            <grid-item
              v-for="(v, i) in gridLayout.layout"
              :key="v.uuid"
              :x="v.x"
              :y="v.y"
              :w="v.w"
              :h="v.h"
              :i="v.uuid"
              :min-w="v.minW"
              :min-h="v.heiH"
              class="card-item card"
              @resized="onResize(v, `refCard${i}`)"
              @moved="movedEvent"
            >
              <component :is="cardData[v['componentName']]" :id="i" :ref="(el:any) => setItemRef(el, `refCard${i}`)">
                <!-- 表格头部信息 -->
                <template #header>
                  <div class="card-header">
                    {{ v.mainTitle }}
                    <template v-if="gridLayout.mode === 'edit'">
                      <span class="remove-btn btn-icon" @click="onRemoveCard(v.uuid)">
                        <a-tooltip title="删除卡片">
                          <delete-outlined />
                        </a-tooltip>
                      </span>
                      <span class="remove-btn btn-icon" @click="onEditCard(v.id)">
                        <a-tooltip title="编辑卡片">
                          <edit-outlined />
                        </a-tooltip>
                      </span>
                    </template>
                  </div>
                </template>
              </component>
            </grid-item>
          </grid-layout>
        </div>
      </div>
    </div>
  </a-spin>

  <XTModuleBIEdit ref="refCardModal" @on-card-succ="onAddCardSucc" />
</template>
<script lang="ts">
import XTModuleBIEdit from "@/components/Business/XTModuleBI/XTModuleBIEdit.vue"
import Card1 from "@/components/Business/XTModuleBI/XTModuleBIChart/XTModuleBar.vue"
import Card2 from "@/components/Business/XTModuleBI/XTModuleBIForm/XTModuleBIFormDate.vue"
import { v4 as uuidv4 } from "uuid"
import { message } from "ant-design-vue"
import cloneDeep from "lodash/cloneDeep"

export default defineComponent({
  name: "ProjectWork",
  components: {
    XTModuleBIEdit,
  },
  setup() {
    //卡片的数据结构
    interface IcardItem {
      x: number
      y: number
      w: number
      h: number
      minW: number
      heiH: number
      i: string // i是栅格中元素唯一 ID, 和v-for循环遍历的 key 要一致了。 uuid的值在添加之后在数据中加的
      id: string //后台给的id
      uuid: string
      mainTitle: string //主标题
      Subtitle: string //副标题
      componentName: string //组件名称，需要和在卡片目录进行对应
      type: string // 卡片分类：基础卡片form和报表卡片chart
      showWorkbench: boolean //是否在工作台展示该组件
      already: boolean //是否后台以后该卡片数据
      [propName: string]: any
    }

    //gridLayout 数据格式
    interface IgridLayout {
      layout: IcardItem[]
      colNum: number
      isresizable: boolean
      isdraggable: boolean
      spinning: boolean
      mode: string
      tip: string
      workbenchUpdate: boolean //是否更新数据，没有更新不走接口
    }

    //1. 存储卡片组件
    const cardData = { Card1, Card2 }

    //2. 每个卡片的id，添加的使用把卡片的唯一值uuid传入即可
    let workCardIds: any = []

    //3. 卡片列表数据
    let cardList: Array<IcardItem> = []

    const refCardModal = shallowRef()
    const cardIdObj = {}

    //4. 布局数据
    const gridLayout: IgridLayout = reactive({
      layout: [],
      colNum: 12,
      isresizable: false,
      isdraggable: false,
      mode: "show",
      spinning: true,
      tip: "工作台初始化中...",
      workbenchUpdate: false,
    })

    //编辑卡片 - 进入编辑卡片模式
    const onEditCardMode = () => {
      gridLayout.mode = "edit"
      gridLayout.isdraggable = true
      gridLayout.isresizable = true
    }

    //添加卡片 - 打开添加卡片弹框
    const onOpenAddCardPop = () => {
      refCardModal.value?.setOpen()
    }

    /**
     * 完成编辑
     *  1. 发送ajax传送到后台进行保存数据
     *  2. 修改为显示模式
     */
    const onEditSucc = () => {
      //更新了走接口
      if (gridLayout.workbenchUpdate) {
        gridLayout.tip = "数据保存中..."
        gridLayout.spinning = true
        gridLayout.layout = gridLayout.layout.filter((card: IcardItem) => (card.already = true))
        setTimeout(() => {
          gridLayout.spinning = false
          message.success("保存成功")
          console.log("layout - data ...", gridLayout.layout)
          console.log(JSON.stringify(gridLayout.layout))
          gridLayout.mode = "show"
          gridLayout.isdraggable = false
          gridLayout.isresizable = false
          gridLayout.workbenchUpdate = false
        }, 1000 * 1)
      } else {
        onCalcelEdit()
      }
    }

    //取消编辑
    const onCalcelEdit = () => {
      gridLayout.mode = "show"
      gridLayout.isdraggable = false
      gridLayout.isresizable = false
    }

    //添加卡片 - 进行数据回显到工作台
    const onAddCardSucc = (card: IcardItem) => {
      const uuid = uuidv4()
      let newCard = cloneDeep(card)
      newCard = { ...newCard, uuid, showWorkbench: true, already: false }
      workCardIds.push({
        uuid: uuid,
        already: false,
      })
      cardList.push(cloneDeep(newCard))
      initWorkbench()
    }

    //删除卡片 -  逻辑删除
    const onRemoveCard = (uuid: string) => {
      let index = -1
      gridLayout.layout.forEach((card: IcardItem, i) => {
        if (card.uuid === uuid) index = i
      })
      // 将已添加到卡片id数据池，将该卡片移除掉
      workCardIds = workCardIds.filter((v: any) => v.uuid !== uuid)
      gridLayout.layout.splice(index, 1)
      cardList = cloneDeep(gridLayout.layout)
      gridLayout.workbenchUpdate = true

      // 删除完毕是否更新布局
      // initWorkbench()
    }

    // 编辑卡片 - 弹框进行编辑
    const onEditCard = (val: string) => {
      console.log("onEditCard ...", val)
    }

    //修改卡片大小 - 图表进行联动
    const onResize = (card: IcardItem, cardRefName: string) => {
      gridLayout.workbenchUpdate = true
      //只有图表组件{echarts}才进行执行resize方法自适应组件大小，其他基础组件采用flex自适应布局即可。
      if (card?.type === "chart") cardIdObj[cardRefName]?.reRender()
      cardList = cloneDeep(gridLayout.layout)
    }

    //移动后事件
    const movedEvent = () => {
      gridLayout.workbenchUpdate = true
    }

    /**
     * 获取工作台卡片数据, 初始化工作台
     */
    const workbenchEntry = () => {
      // ajax
      setTimeout(() => {
        cardList = [
          {
            x: 0,
            y: 0,
            w: 4,
            h: 4,
            i: "5d0c3cca-43d9-4673-9cbd-4dc94c89bf35",
            uuid: "5d0c3cca-43d9-4673-9cbd-4dc94c89bf35",
            id: "100",
            mainTitle: "卡片17",
            Subtitle: "共5个工作项",
            minW: 2,
            heiH: 2,
            componentName: "Card1",
            type: "chart",
            showWorkbench: true,
            already: true,
            moved: false,
          },
        ]
        cardList.forEach((v: IcardItem) => {
          const obj = {
            uuid: v.uuid,
            already: v.already,
          }
          if (v.showWorkbench) workCardIds.push(obj)
        })
        gridLayout.spinning = false
        gridLayout.layout = cloneDeep(cardList)
      }, 1000 * 3)
    }

    //初始化工作台
    const initWorkbench = () => {
      let lengthNum = 0
      gridLayout.layout = []
      gridLayout.workbenchUpdate = true
      workCardIds.forEach((idObj: { uuid: string; already: boolean }) => {
        const cardObj = cardList.filter((v: IcardItem) => v.uuid === idObj.uuid)?.[0]
        if (!cardObj) return
        if (cardObj.already) {
          gridLayout.layout.push(cardObj)
        } else {
          //判断是新添加卡片寻找位置 还是已有工作台卡了的位置，工作台以后卡片，不进行遍历叠加处理，使用已有坐标即可。
          const card: IcardItem = {
            x: cardObj.x == 0 ? (lengthNum + cardObj.w > 12 ? 0 : lengthNum) : cardObj.x,
            y: cardObj.y == 0 ? gridLayout.layout.length + 1 : cardObj.y,
            w: cardObj.w,
            h: cardObj.h,
            i: cardObj.uuid,
            uuid: cardObj.uuid,
            id: cardObj.id,
            mainTitle: cardObj.mainTitle,
            Subtitle: cardObj.Subtitle,
            minW: cardObj.minW,
            heiH: cardObj.heiH,
            componentName: cardObj.componentName,
            type: cardObj.type,
            showWorkbench: cardObj.showWorkbench,
            already: cardObj.already,
          }
          lengthNum = cardObj.w + lengthNum > 11 ? 0 : cardObj.w + lengthNum
          gridLayout.layout.push(card)
        }
      })
    }

    //存储每个组件动态的ref值，用来后期更改卡片大小，里面的图表进行联动
    const setItemRef = (el: any, cardRefName: string) => {
      if (el) cardIdObj[cardRefName] = el
    }

    // 入口
    workbenchEntry()

    return {
      gridLayout,
      onResize,
      onRemoveCard,
      onEditCard,
      onEditCardMode,
      onOpenAddCardPop,
      onEditSucc,
      onCalcelEdit,
      cardData,
      refCardModal,
      onAddCardSucc,
      setItemRef,
      movedEvent,
    }
  },
})
</script>
<style scoped lang="less">
.work-page {
  overflow: hidden;
  max-height: 100vh;

  // 卡片工作区
  .vue-grid-layout-tobbar {
    margin-bottom: 10px;
    background-color: #fff;
    padding: 10px 0;
    box-shadow: 0 0 2px 0 rgba(31, 31, 31, 0.05), 0 1px 2px 0 rgba(31, 31, 31, 0.15);
    z-index: 10;
    display: flex;
    .info-view {
      flex-basis: 300px;
    }
    .btn-group {
      text-align: right;
      :deep(.ant-btn:not(:last-child)) {
        margin-right: 15px;
      }
    }
  }

  // 卡片内容部分
  .vue-grid-layout-content {
    overflow-y: scroll;
    height: 100vh;
    box-sizing: border-box;
    padding-bottom: 80px;
    &::-webkit-scrollbar {
      width: @webkit-scrollbar-width;
      height: @webkit-scrollbar-height;
    }
    &::-webkit-scrollbar-thumb {
      background-color: @webkit-scrollbar-thumb-modal;
    }
    .layout-box-view {
      position: relative;
      left: -10px;
      padding-bottom: 42px; //留出下面的一段距离，进行线下拖拽
      min-height: 900px;
      overflow-y: hidden;
      background-size: 8.276% 110px !important; //比row-height 高 10px, 进行宫格排列
      background-color: #efefef;
      background-image: linear-gradient(0deg, #f8f8f8 10px, transparent 0.1em), linear-gradient(90deg, #f8f8f8 10px, transparent 0.1em);
    }

    .grid-layout-comp {
      .vue-grid-item {
        background-color: #fff;
        // box-shadow: 0 4px 6px 0 rgb(31 31 31 / 5%), 0 0 2px 0 rgb(31 31 31 / 20%);
        // border: 1px solid #d3d3d3;
        box-shadow: 0 1px 2px 0 rgba(31, 31, 31, 0.05), 0 1px 2px 0 rgba(31, 31, 31, 0.15);
        &.cssTransforms {
          top: -9px;
        }
      }
      //卡片组件 头部信息
      .card {
        transition: all 0.5s ease;
      }
      .card:hover {
        box-shadow: 0 10px 10px 0 #d3d3d3;
        cursor: grab;
      }
      .card-header {
        padding: 15px 10px;
        // border-top: 1px solid #d3d3d3;
        .remove-btn {
          display: block;
          float: right;
          cursor: pointer;
          margin-left: 15px;
        }
      }
    }

    .bg-show-mode {
      min-height: 100vh;
      background-color: #f8f8f8;
      /* overflow-y: scroll; */
    }
  }
}
//占位符样式
:deep(.vue-grid-placeholder) {
  background: #5e5c5c !important;
  opacity: 0.2;
  transition-duration: 100ms;
  z-index: 2;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  -o-user-select: none;
  user-select: none;
}
</style>
